﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using InsightAuto.Domain.Core;
using System.Data.Objects;

namespace InsightAuto.Web
{
    public class DbInitializer
    {
        static Random random = new Random(DateTime.Now.Millisecond * DateTime.Now.DayOfYear);

        Action<CoreContainer> Initializer;

        public static void InitCore(CoreContainer context)
        {
            Action<CoreContainer>[] inits = new Action<CoreContainer>[]
            { 
                InitCarClass,
                InitCar,
                InitDealer,
                InitPrice,
                InitAdvertise,
                InitArticleCategory,
                InitArticle,
            };

            foreach (var init in inits)
            {
                init(context);
                context.SaveChanges();
            }
        }

        private static void InitCarClass(CoreContainer context)
        {
            string[] classes = {
                                "微型车",
                                "小型车",
                                "紧凑型车",
                                "中型车",
                                "中大型车",
                                "豪华车",
                                "MPV",
                                "SUV",
                                "跑车",
                               };

            var inits = from c in classes
                        select new CarClass() { Name = c };

            AddToContext(inits, context.CarClasses, new PropertyComparer<CarClass, string>(o => o.Name));
            context.SaveChanges();
        }

        private static void InitPrice(CoreContainer context)
        {
            if (context.Prices.Count() >= context.Models.Count() * context.Dealers.Count())
                return;

            var inits = from dealer in context.Dealers.ToList()
                        from model in context.Models.ToList()
                        select new Price()
                        {
                            Dealer = dealer,
                            Model = model,
                            Time = DateTime.Now,
                            Value = Math.Round(random.NextDouble() * random.Next(20, 200), 2),
                        };

            AddToContext(inits, context.Prices);
        }

        private static void InitDealer(CoreContainer context)
        {
            List<Dealer> inits = new List<Dealer> {
                new Dealer(){ Name="奔驰专卖店", Address="东一路", Fax="12345678", Phone="764234234"},
                new Dealer(){ Name="宝马专卖店", Address="南2路", Fax="346245", Phone="54234"},
                new Dealer(){ Name="奥迪专卖店", Address="北3路", Fax="34523", Phone="21341256"},
                new Dealer(){ Name="大众专卖店", Address="西4路", Fax="574567347", Phone="2153234"},
                new Dealer(){ Name="雷克萨斯专卖店", Address="中山路", Fax="23423516", Phone="2342135"},
                new Dealer(){ Name="奇瑞专卖店", Address="北京路", Fax="3452345", Phone="235621543"},
            };

            AddToContext(inits, context.Dealers, new PropertyComparer<Dealer, string>(o => o.Name));
        }

        private static void InitCar(CoreContainer context)
        {
            List<Manufacturer> manufacturers = new List<Manufacturer>()
            {
                new Manufacturer(){ Name="大众"},
                new Manufacturer(){ Name="宝马"},
                new Manufacturer(){ Name="奥迪"},
                new Manufacturer(){ Name="奇瑞"},
                new Manufacturer(){ Name="奔驰"},
                new Manufacturer(){ Name="雷克萨斯"},
                new Manufacturer(){ Name="现代"},
                new Manufacturer(){ Name="福特"},
                new Manufacturer(){ Name="比亚迪"},
                new Manufacturer(){ Name="三菱"},
            };

            string[] brandPrefix = { "国产", "进口", "山寨" };
            var carClasses = context.CarClasses.ToList();
            var notInDatabase = manufacturers.Except(context.Manufacturers, new PropertyComparer<Manufacturer, string>(m => m.Name));
            foreach (var manufacturer in notInDatabase)
            {
                var brands = from p in brandPrefix
                             select new Brand() { Name = p + manufacturer.Name, Manufacturer = manufacturer };

                //AddToContext(brands, context.Brands);
                
                foreach (var brand in brands)
                {
                    var series = from c in "ABCDEFG".ToCharArray()
                                 select new Series()
                                 {
                                     Name = string.Format("{0} 系列", c),
                                     Brand = brand,
                                     Class = carClasses[random.Next(carClasses.Count)],
                                 };

                    //AddToContext(series, context.Series);
                    
                    foreach (var s in series)
                    {
                        var models = from y in Enumerable.Range(2000, 10)
                                     select new Model()
                                     {
                                         Name = string.Format("{0} {1}", brand.Name, y.ToString()),
                                         Series = s,
                                         Detail = RandomModelDetail(),
                                     };

                        AddToContext(models, context.Models);
                    }

                }

            }

            //AddToContext(notInDatabase, context.Manufacturers);

        }

        private static ModelDetail RandomModelDetail()
        {
            var result = new ModelDetail();

            var type = typeof(ModelDetail);
            var properties = type.GetProperties();
            foreach (var p in properties)
            {
                object value = null;
                if (p.PropertyType == typeof(Double?))
                {
                    value = Math.Round(random.NextDouble() * 100, 2);
                }
                else if (p.PropertyType == typeof(string))
                {
                    value = "abcd";
                }
                else if (p.PropertyType == typeof(Int32?))
                {
                    value = random.Next(2000);
                }

                if (value != null)
                {
                    p.SetValue(result, value, null);
                }
            }

            return result;
        }

        private static void InitArticle(CoreContainer context)
        {
            int articleCountOfEachCategory = 50;

            var categories = from ac in context.ArticleCategories
                             where ac.Articles.Count < articleCountOfEachCategory
                             select ac;

            var prototype = context.Articles.FirstOrDefault();
            if (prototype == null)
            {
                prototype = new Article() { Category = null, Content = "Hello", Title = "Hello World", Submitter = "aa", SubmitTime = DateTime.Now };
            }

            foreach (var category in categories)
            {
                var random = new Random(DateTime.Now.Millisecond);

                while (category.Articles.Count < articleCountOfEachCategory)
                {
                    var article = new Article()
                    {
                        Category = category,
                        Content = prototype.Content,
                        Title = prototype.Title,
                        Submitter = prototype.Submitter,
                        SubmitTime = prototype.SubmitTime.AddHours(random.NextDouble() * -300)
                    };

                    category.Articles.Add(article);
                }
            }
        }

        private static void InitArticleCategory(CoreContainer context)
        {
            List<ArticleCategory> inits = new List<ArticleCategory> {
                new ArticleCategory() { Name = "商家新闻"},
                new ArticleCategory() { Name = "热门促销"},
                new ArticleCategory() { Name = "车展消息"},
                new ArticleCategory() { Name = "试驾报道"},
                new ArticleCategory() { Name = "热门车型"},
                new ArticleCategory() { Name = "最新消息"},
                new ArticleCategory() { Name = "用车养车"},
                new ArticleCategory() { Name = "新车导购"},
                new ArticleCategory() { Name = "对比评测"},
                new ArticleCategory() { Name = "省油技巧"},
                new ArticleCategory() { Name = "赛事精选"},
                new ArticleCategory() { Name = "品牌资讯"},
            };

            AddToContext(inits, context.ArticleCategories, new PropertyComparer<ArticleCategory, string>(ac => ac.Name));
        }

        private static void InitAdvertise(CoreContainer context)
        {
            List<AdvertisePosition> inits = new List<AdvertisePosition> {
                new AdvertisePosition() { PositionCode = "head", Remark = "顶部广告" },
                new AdvertisePosition() { PositionCode = "main_ad_1", Remark = "主页横幅广告1" },
                new AdvertisePosition() { PositionCode = "main_ad_2", Remark = "主页横幅广告2" }
            };

            AddToContext(inits, context.AdvertisePositions, new PropertyComparer<AdvertisePosition, string>(ap => ap.PositionCode));
        }

        private static void AddToContext<T>(IEnumerable<T> inits, ObjectSet<T> objectSet) where T : class
        {
            AddToContext(inits, objectSet, null);
        }

        private static void AddToContext<T>(IEnumerable<T> inits, ObjectSet<T> objectSet, IEqualityComparer<T> comparer) where T : class
        {
            if (comparer != null)
            {
                var notInDatabase = inits.Except(objectSet, comparer);
                if (notInDatabase.Count() > 0)
                {
                    foreach (var o in notInDatabase)
                        objectSet.AddObject(o);
                }
            }
            else
            {
                foreach (var o in inits)
                    objectSet.AddObject(o);
            }
        }

        class PropertyComparer<T, TProperty> : IEqualityComparer<T>
        {
            Func<T, TProperty> propertyRetriver;

            public PropertyComparer(Func<T, TProperty> property)
            {
                if (property == null)
                {
                    throw new ArgumentNullException();
                }

                propertyRetriver = property;
            }

            #region IEqualityComparer<T> 成员

            public bool Equals(T x, T y)
            {
                return propertyRetriver(x).Equals(propertyRetriver(y));
            }

            public int GetHashCode(T obj)
            {
                return propertyRetriver(obj).GetHashCode();
            }

            #endregion
        }
        
        /*
        class PositionCodeComparer : IEqualityComparer<AdvertisePosition>
        {

            public bool Equals(AdvertisePosition x, AdvertisePosition y)
            {
                return x.PositionCode.Equals(y.PositionCode);
            }

            public int GetHashCode(AdvertisePosition obj)
            {
                return obj.PositionCode.GetHashCode();
            }
        }

        class NamedObjectComparer : IEqualityComparer<INamedObject>
        {
            #region IEqualityComparer<INamedObject> 成员

            public bool Equals(INamedObject x, INamedObject y)
            {
                return x.Name.Equals(y.Name);
            }

            public int GetHashCode(INamedObject obj)
            {
                return obj.Name.GetHashCode();
            }

            #endregion
        }

        class CategoryNameComparer : IEqualityComparer<ArticleCategory>
        {
            #region IEqualityComparer<ArticleCategory> 成员

            public bool Equals(ArticleCategory x, ArticleCategory y)
            {
                return x.Name.Equals(y.Name);
            }

            public int GetHashCode(ArticleCategory obj)
            {
                return obj.Name.GetHashCode();
            }

            #endregion
        }

        class BrandNameComparer : IEqualityComparer<Brand>
        {
            #region IEqualityComparer<Brand> 成员

            public bool Equals(Brand x, Brand y)
            {
                return x.Name.Equals(y.Name);
            }

            public int GetHashCode(Brand obj)
            {
                return obj.Name.GetHashCode();
            }

            #endregion
        }

        class ManufacturerNameComparer : IEqualityComparer<Manufacturer>
        {
            #region IEqualityComparer<Manufacturer> 成员

            public bool Equals(Manufacturer x, Manufacturer y)
            {
                return x.Name.Equals(y.Name);
            }

            public int GetHashCode(Manufacturer obj)
            {
                return obj.Name.GetHashCode();
            }

            #endregion
        }

        */
    }
}